// Arrray 类型
let list : number[] =[1,2,3];
let list_frist : Array<number> = [1,2,3]
console.log(list,list_frist);
// Enum类型 在枚举中
enum Direction {
  NORTH='NORTH',
  SOUTH='SOUTH',
  EAST='EAST',
  WEST='WEST'
}
let dir: Direction = Direction.NORTH
console.log(dir);
// Any（动态类型）
let notSure : any = 4;
notSure = 'maybe a string instead'
notSure = false ;
var notFalse = 4;
// notFalse = 'maybe a string instead';   error : notFalse must be number


// Tuple元组 类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。比如,你可以定义一对值分别为string 和 number 类型的元组

let  x : [string,number];

x = ['17355479252', 12]
// x = ['男', 23] 不能将类型“number”分配给类型“string”。ts(2322)

console.log(x[0].substr(1));
console.log(x[0]);

// 当访问一个越界的元素,会使用联合类型替代: 着重考虑  TS的  编码规则
// Void 
// 在某种程度上来说, void 类型像是与any 类型相反的,它表示没有任何类型数据.当一个函数没有返回值的时候,你通常会见到其返回值类型是:void:
function warnUser(): void {
  console.log("this is my warning message");
}
warnUser()
function warnSelf(): number{
  console.log("this is my warnSelf message");
  return 2+3
}
console.log(warnSelf());
// Null and Underfined

// TypeScript 里 ,underfined和null两者 各自有自己的类型分别叫做 undefined和null
let u: undefined = undefined;
let n: null = null; 
// 默认情况下, null和undefined 是所有类型的子类型. 就是说  你可以把null 和 undefined 复制给 number 类型的变量. 然而, 当你指定了
// 
let someValue: any="this is a TypeScript";
let strLength: number =someValue.length
// "尖括号" 语法
let strLengthFrist: number = (<string>someValue).length
// as 语法
let someValueSceond: any = "this is a Lorenzo";
let strLengthSceond: number = (someValueSceond as string).length;
console.log(strLength);
console.log(strLengthFrist);
console.log(strLengthSceond);



// TypeScipt Union Types and Type Aliases
//  Union Types 
// let greet = (message : string | string[]) =>{
//   if(message instanceof Array) {
//     let messages = "";
//     message.forEach((msg) => {
//       messages += `${msg}`;
//     });
//     console.log("Received messages ", messages);
//   } else {
//     console.log("Received message =",message);
//   }
// };
// greet('semlinker')
// greet(['Hello','Angular'])

// Type Aliases
type Message = string | string[];
let greet = (message: Message)=>{
  if(message instanceof Array) {
    let messages = "";
    message.forEach((msg) => {
      messages += `${msg}`;
    });
    console.log("Received messages ", messages);
  } else {
    console.log("Received message =",message);
  }
};
greet('semlinker')
greet(['Hello','Angular'])

// TypeScipt Interface 
interface Person {
  uersName: string;
  age: number;
}
let semlinker: Person = {
  uersName:'Lorenzo',
  age:31,
};
console.log(semlinker);
// 可选 | 只读属性
interface Student {
  readonly name: string;
  age?: number;
}
let Studentker: Student = {
  name:'Lorenzo',
  // age:31,
};
// 只读属性用于限制 只能在对象刚刚创建的时候修改其值。 ReadonlyArray<T> 类型, 它与Array<T> 相似 只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改了。
let a: number[] = [1,2,3,4,5];
let ro: ReadonlyArray<number> = a;

// ro[0] = 12; error
// ro[1] = 12; error
// ro[2] = 12; error
// ro[3] = 12; error
// ro[4] = 12; error
console.log(ro[1]);
// ro.push[5]; error
console.log(ro.length);

/**
 * TypeScipt Class 
 * 在面向对象语言中,类是一种面向对象计算机变成语言的构造，是创建对象的蓝图，免俗了所创建的对象共同的属性和方法。
 * 在TypeScript中，我们可以通过class关键字来定义一个类。
 *  */ 
class Greeter {
  static cname : string = 'Greeter'; //静态属性
  greeting: string; // 成员属性
  constructor(message: string) {
    // 构造函数 - 执行初始化操作
    this.greeting = message
  }
  static getClassName(): string {
    // 静态方法
    return  'Class name is Greeter'
  }
  greet() { 
    // 成员方法
    return 'Hello, ' + this.greeting
  }
}
let greeter = new Greeter("world")
console.log(greeter);
console.log(greeter.greet());
console.log(Greeter.getClassName());
//  TypeScrpt Accessors 在 TypeScript 中，我们可以通过getter 和 setter 方法来实现数据的封装和有效性校验，防止出现异常数据。
let passcode  = "hello angular js";
class Employee {
  private _fullName: string;

  get fullName(): string {
    return this._fullName
  }
  set fullName(newName: string){
    if(passcode && passcode == "hello angular 5") {
      this._fullName = newName
    }
    else {
      console.log("Error: Unauthorized update of employee!"); 
    }
  }
}
let employee = new  Employee();
employee.fullName = "Bob Smith"
if (employee.fullName) {
  console.log(employee.fullName);
  
}
/**
 * TypeScript Inheritance
 * 继承(Inheritance) 是一种联结类与类的层次模型。指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能，
 * 并可以增加它自己的新功能的能力，继承是类与类或者接口与接口之间的最常见的关系;  继承是一种 is-a关系
 * */
class Animal {
  name: string;
  constructor(theName: string) {
      this.name = theName
  }
  move(distanceInMeters: number = 0) {
    console.log(`${this.name} move ${distanceInMeters}`);
  }
}
class Snake extends Animal {
  constructor(name: string) {
    super(name);
  }
  move(distanceInMeters = 5){
    console.log("Slithering...");
    super.move(distanceInMeters)
  }
}
let sam = new Snake('Sammy the Python');
sam.move();


/**
 * TypeScript Generics
 * 泛型（Generics） 允许同一个函数接收不同类型参数的一种模板。
 */
// interface GenericIdentityFn<T> {
//   (arg: T) : T
// }

class GenericIdentityFn<T> {
  Value: T;
  add: (x: T, y: T) => T
}
let myGenericNumber = new  GenericIdentityFn<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y ){
  return x+y
}
// 案例：
interface Hero { // Hero 接口
  id: number;
  name: string;
}



console.log("hello");
